﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Net.Sockets;
using System.Text;
using System.Threading;
using System.Threading.Tasks;

namespace SocketServer
{
    class Program
    {
        static void Main(string[] args)
        {
            StartServer();
        }


        private static int m_SocketCount = 0;
        private static ManualResetEvent mManualResetEvent = new ManualResetEvent(false);

        public static void StartServer()
        {
            IPEndPoint ipEndPoint = new IPEndPoint(IPAddress.Parse("127.0.0.1"), 1354);
            Socket serverSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
            try
            {
                serverSocket.Bind(ipEndPoint);
                serverSocket.Listen(20);
                Console.WriteLine("Server Start");
                while (true)
                {
                    mManualResetEvent.Reset();
                    serverSocket.BeginAccept(new AsyncCallback(Accept), serverSocket);
                    mManualResetEvent.WaitOne();
                }
            }
            catch (Exception ex)
            {
                Console.WriteLine("Exception:\n" + ex);
            }
        }


        public static void Accept(IAsyncResult result)
        {
            mManualResetEvent.Set();

            Socket serverSocket = (Socket)result.AsyncState;

            Console.WriteLine("Accept one client " + (++m_SocketCount));

            Socket receiverSocket = serverSocket.EndAccept(result);

            StateObject state = new StateObject();
            state.mCurrentSocket = receiverSocket;

            receiverSocket.BeginReceive(state.mBuffer, 0, StateObject.mBufferSize, 0, new AsyncCallback(ReceiveCallback),
                state);
        }

        public static void ReceiveCallback(IAsyncResult result)
        {
            string content = String.Empty;
            StateObject state = (StateObject)result.AsyncState;
            Socket receiverSocket = state.mCurrentSocket;
            try
            {
                int byteRead = receiverSocket.EndReceive(result);
                if (byteRead > 0)
                {
                    byte[] dateLengthArr = new byte[4];
                    Buffer.BlockCopy(state.mBuffer, 0, dateLengthArr, 0, 4);
                    int dataLength = BitConverter.ToInt32(dateLengthArr, 0);
                    Console.WriteLine("receive data length = " + dataLength.ToString());

                    byte[] dataArray = new byte[byteRead - 4];
                    Buffer.BlockCopy(state.mBuffer, 4, dataArray, 0, byteRead - 4);
                    state.mStringBuilder.Append(Encoding.ASCII.GetString(dataArray, 0, byteRead - 4));

                    content = state.mStringBuilder.ToString();

                    if (!(byteRead - 4 < dataLength))
                    {
                        Console.WriteLine("Receive " + content.Length + "  " + content);

                        Send(receiverSocket, "success from server");
                    }
                    else
                    {
                        receiverSocket.BeginReceive(state.mBuffer, 0, StateObject.mBufferSize, 0,
                            new AsyncCallback(ReceiveCallback), state);
                    }
                }
            }
            catch (Exception ex)
            {
                Console.WriteLine(ex.ToString());

            }
        }

        public static void Send(Socket hander, String data)
        {
            byte[] byteData = Encoding.ASCII.GetBytes(data);
            try
            {
                hander.BeginSend(byteData, 0, byteData.Length, 0, new AsyncCallback(SendCallback), hander);
            }
            catch (Exception ex)
            {
                Console.WriteLine(ex.ToString());
            }
        }

        public static void SendCallback(IAsyncResult result)
        {
            try
            {
                Socket handler = (Socket)result.AsyncState;
                int bytesSend = handler.EndSend(result);
                Console.WriteLine("Sent {0} bytes to client.", bytesSend);
               
                handler.Shutdown(SocketShutdown.Both);
                handler.Close();

                handler.Listen(20);
                handler.BeginAccept(new AsyncCallback(Accept), handler);
            }
            catch (Exception ex)
            {
                Console.WriteLine(ex.ToString());
            }
        }

        public class StateObject
        {
            public Socket mCurrentSocket = null;
            public const int mBufferSize = 1024;
            public byte[] mBuffer = new byte[mBufferSize];
            public StringBuilder mStringBuilder = new StringBuilder();
        }
    }



}
